package cn.topcodes.tcsf.admin.service.impl;

import cn.topcode.unicorn.utils.ByteUtil;
import cn.topcode.unicorn.utils.Digests;
import cn.topcode.unicorn.utils.StringUtil;
import cn.topcodes.tcsf.admin.commons.domain.Page;
import cn.topcodes.tcsf.admin.commons.domain.ValueRangeConstant;
import cn.topcodes.tcsf.admin.commons.generic.GenericService;
import cn.topcodes.tcsf.admin.domain.entity.SysOperateLog;
import cn.topcodes.tcsf.admin.domain.entity.SysRole;
import cn.topcodes.tcsf.admin.domain.entity.SysUser;
import cn.topcodes.tcsf.admin.domain.entity.SysUserRoleRela;
import cn.topcodes.tcsf.admin.domain.form.UpdateSysUserForm;
import cn.topcodes.tcsf.admin.mapper.SysUserMapper;
import cn.topcodes.tcsf.admin.mapper.SysUserRoleRelaMapper;
import cn.topcodes.tcsf.admin.service.org.SysRoleService;
import cn.topcodes.tcsf.admin.service.org.SysUserService;
import com.google.common.base.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import tk.mybatis.mapper.entity.Example;

import javax.persistence.EntityNotFoundException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
@Transactional(readOnly=true)
public class SysUserServiceImpl extends GenericService<SysUser> implements SysUserService {

	@Autowired
	private SysUserRoleRelaMapper sysUserRoleRelaMapper;

	@Autowired
	private SysUserMapper sysUserMapper;

	@Autowired
	private SysRoleService sysRoleService;

	@Override
	public boolean isOnline(long userId) {

		return false;
	}

	@Override
	public List<SysUser> findAllOnline(Example example) {

		return null;
	}

	@Override
	public List<SysUser> findAllOnline(Map<String, String> searchParams) {

		return null;
	}

	@Override
	public Page<SysUser> findPageOnline(Example example, int pageNumber, int pageSize) {

		return null;
	}

	@Override
	public Page<SysUser> findPageOnline(Map<String, String> searchParams, int pageNumber, int pageSize) {

		return null;
	}

	@Override
	public void forcedOffline(long userId) {
		
	}

	@Override
	public SysUser findByUsername(String username) {
		Example example = this.buildExample();
		example.or().andEqualTo("username", username);
		return this.findOne(example);
	}
	
	@Override
	public Long create(SysUser user) {
		Assert.notNull(user);
		if(!Strings.isNullOrEmpty(user.getPassword())) {
			this.entryptPassword(user);
		}
		return super.create(user);
	}

	@Override
	@Transactional(readOnly=false)
	public void register(SysUser user, Long roleId, String ip) {
		Assert.notNull(user);
		user.setRegisterIp(ip);
		user.setRegisterTime(new Date());
		this.create(user);
		this.setRole(user.getId(),roleId);
	}

	@Override
	@Transactional(readOnly=false)
	public void setRole(Long userId, Long roleId) {
		Assert.notNull(userId,"用户ID不能为空");
		Assert.notNull(roleId,"角色ID不能为空");
		Example example = new Example(SysUserRoleRela.class);
		example.or().andEqualTo("userId",userId);
		this.sysUserRoleRelaMapper.deleteByExample(example);
		SysUserRoleRela rela = new SysUserRoleRela();
		rela.setCreatedTime(new Date());
		rela.setUpdatedTime(new Date());
		rela.setDataState(ValueRangeConstant.DataState.DATA_STATE_ENABLE);
		rela.setRoleId(roleId);
		rela.setUserId(userId);
		this.sysUserRoleRelaMapper.insert(rela);
	}

	@Override
	@Transactional(readOnly = false)
	public void update(SysUser user) {
		Assert.notNull(user);
		Assert.hasText(user.getPassword());
		SysUser entity = this.findOne(user.getId());
		if(!entity.getPassword().equals(user.getPassword())) {
			entryptPassword(user);
		}
		super.update(user);
	}

	@Override
	@Transactional(readOnly = false)
	public void update(UpdateSysUserForm form) {
		Assert.notNull(form);
		Assert.notNull(form.getId());
		SysUser user = this.findOne(form.getId());
		Assert.notNull(user);
		user.setUsername(form.getUsername());
		user.setRealName(form.getRealName());
		user.setGender(form.getGender());
		user.setDeptId(form.getDeptId());
		user.setDescription(form.getDescription());
		user.setEmail(form.getEmail());
		user.setTel(form.getTel());
		this.update(user);
		this.setRole(form.getId(),form.getRoleId());
	}

	/**
	 * 设定安全的密码，生成随机的salt并经过1024次 sha-1 hash
	 */
	private void entryptPassword(SysUser user) {
		byte[] salt = Digests.generateSalt(SALT_SIZE);
		user.setSalt(ByteUtil.byte2Hex(salt));
		user.setPassword(getEncodePwd(user.getPassword(), salt));
	}

	private String getEncodePwd(String plainPwd, byte[] salt) {
		byte[] hashPassword = Digests.sha1(plainPwd.getBytes(), salt, HASH_INTERATIONS);
		return ByteUtil.byte2Hex(hashPassword);
	}

	@Override
	public boolean isPwdEqual(String plainPwd, SysUser user) {
		byte[] salt = ByteUtil.hex2byte(user.getSalt());
		String encodePwd = getEncodePwd(plainPwd, salt);
		return encodePwd.equals(user.getPassword());
	}

	@Override
	@Transactional(readOnly=false)
	public void login(String username, String password, Boolean rememberMe, String ip) {
		//	登录成功，记录最后登录ip和登录时间
		SysUser user = this.findByUsername(username);
		user.setLastLoginIp(ip);
		user.setLastLoginTime(new Date());

		logGeneric(SysOperateLog.TYPE_USER, "登录");

		this.update(user);
	}
	
	@Transactional(readOnly=false)
	public void logout() {
		logGeneric(SysOperateLog.TYPE_USER, "退出");
	}

	@Override
	@Transactional(readOnly=false)
	public void modifyPassword(long userId, String orginalPassword, String newPassword) {
		SysUser user = this.findOne(userId);
		Assert.notNull(user);
		Assert.hasText(orginalPassword);
		Assert.hasText(newPassword);
		if(isPwdEqual(orginalPassword, user)) {
			user.setPassword(newPassword);
			this.entryptPassword(user);
			logGeneric(SysOperateLog.TYPE_USER, "修改用户密码，用户ID:" + userId);
			super.update(user);
		}else {
			throw new IllegalArgumentException("原密码输入错误");
		}
	}

	@Override
    public SysRole getRole(Long id) {
        Example example = new Example(SysUserRoleRela.class);
        example.or().andEqualTo("userId",id);
        List<SysUserRoleRela> list = this.sysUserRoleRelaMapper.selectByExample(example);
        if(list.isEmpty())
        	return null;
        return sysRoleService.findOne(list.get(0).getRoleId());
    }

    @Override
	@Transactional(readOnly = false)
    public void resetPassword(Long id, String newPassword) {
		SysUser user = this.findOne(id);
		Assert.notNull(user);
		Assert.hasText(newPassword);
		user.setPassword(newPassword);
		this.entryptPassword(user);
		super.update(user);
    }

	@Override
	@Transactional(readOnly = false)
	public SysUser delete(Long id) {
		SysUser user = this.findOne(id);
		SysRole role = this.getRole(id);
		if(this.isBuildInRole(role.getCode())) {
			Example example = new Example(SysUserRoleRela.class);
			example.or().andEqualTo("roleId",role.getId());
			int count = this.sysUserRoleRelaMapper.selectCountByExample(example);
			if(count <= 1) {
				throw new IllegalArgumentException("删除失败！每个内置角色至少要有一个用户");
			}
		}
		return super.delete(id);
	}

	private boolean isBuildInRole(String code) {
		if(ValueRangeConstant.BuiltInRole.ROLE_DEVELOPER.equalsIgnoreCase(code) ||
				ValueRangeConstant.BuiltInRole.ROLE_ADMIN.equalsIgnoreCase(code) ||
				ValueRangeConstant.BuiltInRole.ROLE_SUPER_ADMIN.equalsIgnoreCase(code)) {
			return true;
		}
		return false;
	}

	@Override
	public List<SysUser> findAll(Long curUserId, String name) {
		boolean isBlank = StringUtil.isBlank(name);
		Example example = this.buildExample();
		boolean isDeveloper = sysRoleService.hasRole(curUserId, ValueRangeConstant.BuiltInRole.ROLE_DEVELOPER);
		if(!isDeveloper || !isBlank) {
			Example.Criteria criteria1 = example.or();
			Example.Criteria criteria2 = example.or();
			if(!isBlank) {
				criteria1.andLike("username","%" + name + "%");
				criteria2.andLike("realName","%" + name + "%");
			}
			if(!isDeveloper) {
				criteria1.andNotIn("id",getDeveloperIds());
				criteria2.andNotIn("id",getDeveloperIds());
			}
		}
		return this.findAll(example);
	}

	private List<Long> getDeveloperIds() {
		Long developerRoleId = this.sysRoleService.getDeveloperRoleId();
		Example example = new Example(SysUserRoleRela.class);
		example.or().andEqualTo("roleId",developerRoleId);
		List<SysUserRoleRela> relas = this.sysUserRoleRelaMapper.selectByExample(example);
		List<Long> ids = new ArrayList<>();
		for(SysUserRoleRela rela : relas) {
			ids.add(rela.getUserId());
		}
		return ids;
	}

	@Override
	public boolean isPwdEqual(String password, Long id) {
		SysUser user = this.findOne(id);
		if(user == null) {
			throw new EntityNotFoundException("管理用户不存在");
		}
		return this.isPwdEqual(password,user);
	}
}
